-- CaveHideItemM
-- Created by chengb Apr/9/2016
-- 洞窟隐藏物件模块

module("CaveHideItemM", package.seeall);

local HIDE_ITEM_DUNGEON_ID = "cave_hide_item";

-- 死亡后延迟播放时间
local DIE_DELAY_TIME = 0.7;

-- 内部函数声明
local getDungeonId;
local tryShowHideItem;
local whenLeaveDungeon;
local whenEquip;
local whenUpgradeEquip;

function init()
    EventMgr.removeAll("CaveHideItemM");

    -- 关注玩家离开迷宫的事件
    EventMgr.register("CaveHideItemM", event.LEAVE_DUNGEON, function(args)
        whenLeaveDungeon(args);
    end);

    -- 关注穿装备的事件
    EventMgr.register("CaveHideItemM", event.EQUIP, function(args)
        whenEquip(args);
    end);

    -- 关注装备升级的事件
    EventMgr.register("CaveHideItemM", event.UPGRADE_EQUIP, function(args)
        whenUpgradeEquip(args);
    end)

    -- 关注点亮
    EventMgr.register("CaveHideItemM", event.TRY_LIGHT_CAVE, function()
        whenLightCave();
    end)
end

-- 获取当前所在的迷宫编号
function getDungeonId()
    if not DungeonInstanceM.isInInstance() then
        return nil;
    end

    local instanceId = DungeonInstanceM.getCurrentInstanceId();
    local intanceInfo = DungeonInstanceM.getInstanceInfo(instanceId);
    return intanceInfo["dungeon_id"];
end

-- 获取当前所在的主关卡编号
function getParentDungeonId()
    if not DungeonM.isInDungeon() then
        return 0;
    end

    local dungeonId = DungeonM.getDungeonId();
    return DungeonAreaM.getParentId(dungeonId);
end

-- 玩家离开迷宫的回调
function whenLeaveDungeon(args)
    if ME.user.dbase:query("hide_item_bonus_stat") ~= nil then
        ME.user.dbase:delete("hide_item_bonus_stat");
    end

    -- 图书奖励信息
    if ME.user.dbase:query("hide_shelf_bonus") ~= nil then
        ME.user.dbase:delete("hide_shelf_bonus");
    end

    -- 删除迷宫抽取到次数记录的信息
    if ME.user.dbase:query("cur_hide_item_stat") ~= nil then
        ME.user.dbase:delete("cur_hide_item_stat");
    end
end

-- 尝试侦测隐藏物件
function tryShowHideItem()
    -- 尝试触发侦测隐藏物件的属性
    local props = PropM.fetchProps(ME.user, "show_hide_item");
    for _, prop in ipairs(props) do
        PropM.trigger(ME.user, prop[1], prop[2]);
    end

    EventMgr.fire(event.FIND_HIDE_ITEM);
end

-- 玩家穿装备的回调
function whenEquip(args)
    local classId = args;
    local equipType = EquipM.query(classId, "type");
    if equipType ~= EQUIP_TYPE_RISKER then
        -- 不是冒险系装备
        return;
    end

    if not canSeeHideItem() then
        -- 看不到隐藏物件
        return;
    end

    -- 尝试侦测隐藏物件
    tryShowHideItem();
end

-- 玩家装备升级的回调
function whenUpgradeEquip(args)
    local classId = args.nextClassId;
    local equipType = EquipM.query(classId, "type");
    if equipType ~= EQUIP_TYPE_RISKER then
        -- 不是冒险系装备
        return;
    end

    if not canSeeHideItem() then
        -- 看不到隐藏物件
        return;
    end

    -- 尝试侦测隐藏物件
    tryShowHideItem();
end

function whenLightCave()
    if not canSeeHideItem() then
        -- 看不到隐藏物件
        return;
    end

    -- 客户端设置提示
    DungeonM.setDungeonMixedField("light_cave_tip", 0);

    -- 尝试侦测隐藏物件
    tryShowHideItem();
end

-- 能否看到隐藏物件
function canSeeHideItem()
    if not DungeonInstanceM.isInInstance() then
        -- 不在副本中
        return false;
    end

    local props = PropM.fetchProps(ME.user, "show_hide_item");
    if #props <= 0 then
        return false;
    end

    -- 不是什么迷宫都会出现得
    local instanceId = DungeonInstanceM.getCurrentInstanceId();
    local instanceInfo = DungeonInstanceM.getInstanceInfo(instanceId) or {};
    if type(instanceInfo["dbase"]) == "table" and
        1 == instanceInfo["dbase"]["not_hide_item"] then
        return false;
    end

    return true;
end

-- 抽取洞窟隐藏物件
function fetchHideItem()
    if not canSeeHideItem() then
        -- 无法看见隐藏物件，不处理
        return {};
    end

    local dungeonId = getDungeonId();
    if type(dungeonId) ~= "number" then
        return {};
    end

    -- 根据dungeon_id获取到的是该迷宫特有的元素
    -- 根据HIDE_ITEM_DUNGEON_ID获取到的是所有迷宫公用的元素
    -- 特殊需求某些洞窟不需要通用元素，调用公式UNNEED_COMM_HIDE_ITEM判断
    local partiElements = DungeonM.getElementsByDungeon(dungeonId) or {};
    local commElements = DungeonM.getElementsByDungeon(HIDE_ITEM_DUNGEON_ID) or {};
    if FormulaM.invoke("UNNEED_COMM_HIDE_ITEM", dungeonId) then
        commElements = {};
    end

    if #table.keys(partiElements) <= 0  and #table.keys(commElements) <= 0 then
        -- 没有配置迷宫元素？
        return {};
    end

    local arr = { partiElements, commElements };
    local waitList = {};

    for _, elements in pairs(arr) do
        for class, list in pairs(elements) do
            local dbase = DungeonM.query(class, "dbase") or {};
            local gridType = DungeonM.query(class, "type");

            local isOverTimes = isClassOverTimes(class);

            if (not isOverTimes) and
                (dbase["hide_item"] or
                 gridType == GRID_TYPE_CAVE_HIDE_ITEM or gridType == GRID_TYPE_SPECIAL_HIDE_ITEM or
                 gridType == GRID_TYPE_ANU_STATUE     or gridType == GRID_TYPE_BROKEN_ROBOT) then
                for _, info in pairs(list) do
                    table.insert(waitList, info);
                end
            end
        end
    end

    if #waitList == 0 then
        return {};
    end

    -- 根据元素id升序
    table.sort(waitList, function(a, b) return a.id < b.id; end);

    -- 根据权重抽取
    local rand = DungeonM.getRandSeed("fetch_hide_item");
    local ret = fetchElemBySeed(waitList, rand);

    statHideClassCount(ret.class);

    return { ["element"] = ret.id, ["class"] = ret.class };
end

-- 计算隐藏物件奖励
function calcHideItemBonus(grid)
    if not grid then
        return {};
    end

    local configBonus = grid.bonus;
    local prefix = "formula_";
    local bonusList = {};

    if type(configBonus) == "table" then
        bonusList = configBonus;
    elseif type(configBonus) == "string" and string.startWith(configBonus, prefix) then
        -- 配置了公式，调用公式计算
        local formulaName = string.sub(configBonus, string.len(prefix) + 1);
        bonusList = FormulaM.invoke(formulaName, ME.user, grid.bonusArg);
    end

    assert(type(bonusList) == "table", "奖励必须为table类型");

    -- 如果只有一种奖励，需要转换一下格式
    if type(bonusList[1]) == 'number' then
        bonusList = { bonusList };
    end

    return {["bonus"] = bonusList,};
end

-- 特殊的隐藏物件奖励（需返回奖励提示）
function calcSpecialHideItemBonus(grid)
    if not grid then
        return {};
    end

    local configBonus = grid.bonus;
    local prefix = "formula_";
    local bonusList = {};

    -- 只支持公式计算奖励（需返回对应的一个奖励提示）
    if type(configBonus) == "string" and string.startWith(configBonus, prefix) then
        -- 配置了公式，调用公式计算
        local formulaName = string.sub(configBonus, string.len(prefix) + 1);
        bonusList = FormulaM.invoke(formulaName, ME.user, grid.bonusArg);
    elseif type(configBonus) == "table" then
        bonusList = configBonus;
    else
        return {};
    end

    assert(type(bonusList) == "table", "奖励必须为table类型");

    return bonusList;
end

-- 统计洞窟的某个特殊奖励出现次数
function statSpecialBonusCount(class)
    local stat = ME.user.dbase:query("hide_item_bonus_stat", {});
    stat[class] = (stat[class] or 0) + 1;
    ME.user.dbase:set("hide_item_bonus_stat", stat);
    trace("CaveHideItemM", "隐藏物件(%d)特殊奖励出现次数更新为：%d", class, stat[class]);
end

-- 获取洞窟的某个特殊奖励出现次数
function getSpecialBonusCount(class)
    local stat = ME.user.dbase:query("hide_item_bonus_stat", {});
    return stat[class] or 0;
end

-- 添加建筑奖励
function addCaveBuildingBonusTimes(class, eventBonus)
    local isOk = FormulaM.invoke("IS_CAVE_HIDE_LIMIT_BONUS", class, eventBonus);

    if not isOk then
        return;
    end

    local  dbase = DungeonM.query(class, "dbase");
    local buffIndex = tonumber(dbase["buff_index"]);

    if buffIndex == 0 then
        return;
    end

    local bonusTimes = 1 + tonumber(BuffDataM.query("cave_limit_bonus", buffIndex));

    BuffDataM.set("cave_limit_bonus", buffIndex, bonusTimes);
end

-- 获得建筑奖励次数
function getCaveBuildingBonusTimes(class)
    local dbase = DungeonM.query(class, "dbase") or {};
    local bufferIndex = tonumber(dbase["buff_index"]);
    if bufferIndex == 0 then
        return 0;
    end

    local times = tonumber(BuffDataM.query("cave_limit_bonus", bufferIndex));
    return times;
end

-- 回答阿努比斯雕塑问题
function answerAnubisStatue(pos, option)
    -- 判断格子是否正确
    local grid = DungeonM.getGridByPos(pos);
    if grid.type ~= GRID_TYPE_ANU_STATUE then
        return false;
    end

    -- 已经失效不管了
    if grid.state == GRID_STATE_DISABLE then
        return false;
    end

    local damage = 0;
    local bonusList = {};
    -- 检查答案
    local isOk = FormulaM.invoke("CHECK_ANUBIS_STATUE_ANSWER", option);
    if isOk then
        -- 计算奖励，执行奖励
        bonusList = FormulaM.invoke("CALC_ANUBIS_BONUS", ME.user);
        local desc = "anubis_bonus";

        if type(bonusList[1]) == "number" then
            BonusM.doBonus(bonusList, desc);
        else
            for _, bonus in pairs(bonusList) do
                BonusM.doBonus(bonus, desc);
            end
        end

        -- 如果抽到洞窟特殊奖励。记录下次数
        addCaveBuildingBonusTimes(grid.class, {["bonus"] = bonusList});
    else
        -- 直接杀死冈布奥
        -- 直接扣血
        damage = ME.user:getHp();
        ME.user:receiveDamage(damage, true);
        ME.user:die({ ["delay"] = DIE_DELAY_TIME, });
    end

    -- 改变状态
    grid:changeState(GRID_STATE_DISABLE);

    -- 回合事件需要在功能做完之后再抛
    if DungeonM.isCostRound(grid) then
        -- 抛出一个回合事件
        EventMgr.fire(event.COMBAT_ROUND, pos);
    end

    -- 抛出事件
    EventMgr.fire(event.ANSWER_ANUBIS_RET, {["isOk"] = isOk, ["damage"] = damage, ["bonus"] = bonusList, ["pos"] = pos});

    -- 通知建筑事件完成
    EventMgr.fire(event.BUILDING_EVENT_DONE, {["pos"] = pos,});

    return true;
end

-- 答案选项
function getAnswerTitle()
    local answers = {};
    for index = 1, 4 do
        local answerTitle = "anubis_answer_" .. index;
        table.insert(answers, getLocStr(answerTitle));
    end

    return answers;
end

-- 使用奖励信息
function recordHideShelfBonus(bonus)
    ME.user.dbase:set("hide_shelf_bonus", bonus);
end

-- 获得奇怪的书架奖励的书籍名称
function getStrangeBookName()
    local activePet = ME.user:getActivePet();
    local petId = activePet.classId;
    local bookName = PetM.query(petId, "books");

    return bookName;
end

--  获取本次迷宫class出现次数
function getHideClassCount(class)
    local curHideItemStat = ME.user.dbase:query("cur_hide_item_stat") or {};

    return tonumber(curHideItemStat[class]);
end

-- 记录本次迷宫class出现次数
function statHideClassCount(class)
    local curHideItemStat = ME.user.dbase:query("cur_hide_item_stat") or {};

    curHideItemStat[class] = 1 + tonumber(curHideItemStat[class]);
    ME.user.dbase:set("cur_hide_item_stat", curHideItemStat);
end

-- 是否超过次数
function isClassOverTimes(class)
    local dbase = DungeonM.query(class, "dbase");
    local timesLimit = dbase["times_limit"];
    if  timesLimit ~= nil and getHideClassCount(class) >= timesLimit then
        return true;
    end

    return false;
end

-- 获得当前奖励描述
function getHideItemTips(class)
    local tips;

    if class == 791 then
        -- 圣者の穿衣镜
        tips = FormulaM.invoke("GET_DRESSING_MIRROR_TIPS");

    elseif class == 794 then

        -- 根据出战冈布奥判断获得奖励的类型，和提示
        local petId = ME.user:getActivePet().classId;
        local bookName = PetM.query(petId, "book_name");

        tips = {getLocStr("cave_hide_shelf_tip"), bookName};

    elseif class == 792 then
        -- 鲜血王座
        tips = FormulaM.invoke("GET_BLOOD_THRONE_TIPS");

    elseif class == 793 then
        tips = FormulaM.invoke("GET_OLD_TERMINAL_TIPS");
    end

    return tips;
end
